package com.floreantpos.jreports;

import com.floreantpos.config.PrintConfig;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperPrintManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRTableModelDataSource;
import net.sf.jasperreports.engine.print.JRPrinterAWT;
import net.sf.jasperreports.engine.util.JRLoader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.floreantpos.main.Application;
import com.floreantpos.model.Guest;
import com.floreantpos.model.Restaurant;
import com.floreantpos.model.Ticket;
import com.floreantpos.model.TicketItem;
import com.floreantpos.model.TicketItemModifier;
import com.floreantpos.model.TicketItemModifierGroup;
import com.floreantpos.model.dao.GuestDAO;
import com.floreantpos.model.dao.RestaurantDAO;
import com.floreantpos.model.dao.TicketDAO;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class JReportPrintService {

  private static Log logger = LogFactory.getLog(JReportPrintService.class);

  public static void printTicket(Ticket ticket) {
    Restaurant restaurant = RestaurantDAO.getInstance().get(Integer.valueOf(1));

    Calendar currentTime = Calendar.getInstance();
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");

    Boolean printGuestName = false;

    Double guestBalance = Double.valueOf(0);
    Boolean printGuestBalance = false;

    if (ticket.getGuest().equals("[Retira]") || !ticket.getGuest().equals(String.valueOf(ticket.getTableNumber()))) {
      printGuestName = true;
    }

    if (ticket.getRegisteredGuest() != null) {
      GuestDAO guestDAO = GuestDAO.getInstance();
      Guest guest = guestDAO.get(ticket.getRegisteredGuest());

      if (guest != null) {
        guestBalance = guest.getCurrentBalance();

        Double paidAmount = Double.valueOf(0);
        if (ticket.getGratuity() != null) {
          paidAmount = ticket.getPaidAmount() + ticket.getGratuity().getAmount();
        } else {
          paidAmount = ticket.getPaidAmount();
        }

        if (!ticket.isPrintedTicket()) {
          if (ticket.isPaymentTicket()) {
            guestBalance = guestBalance + paidAmount;
          } else {
            guestBalance = guestBalance - paidAmount;
          }
        }

        printGuestBalance = true;
      }
    }

    Boolean printPartialPaymentInfo = false;
    if (ticket.isPaid() == false && ticket.getPaidAmount() != 0) {
      printPartialPaymentInfo = true;
    }

    Double gratuityAmount = Double.valueOf(0);
    if (ticket.getGratuityAmount() > 0) {
      gratuityAmount = ticket.getGratuityAmount();
    } else if (ticket.getGratuity() != null && ticket.getGratuity().getAmount() > 0) {
      gratuityAmount = ticket.getGratuity().getAmount();
    }

    HashMap map = new HashMap();
    map.put("headerLine1", restaurant.getName());
    map.put("headerLine2", restaurant.getAddressLine1());
    map.put("headerLine3", restaurant.getAddressLine2());
    map.put("headerLine4", restaurant.getAddressLine3());
    map.put("headerLine5", com.floreantpos.POSConstants.TEL + ": " + restaurant.getTelephone());
    map.put("checkNo", com.floreantpos.POSConstants.CHK_NO + ticket.getId());
    if (!Application.isSaveGuestName() && ticket.getTableNumber() > 0) {
      map.put("tableNo", Application.getControlTypeIdentifier() + ": " + ticket.getTableNumber());
    }
    map.put("guestCount", com.floreantpos.POSConstants.GUESTS_ + ticket.getNumberOfGuests());
    map.put("serverName", com.floreantpos.POSConstants.SERVER + ": " + ticket.getOwner());
    map.put("printGuestName", printGuestName);
    map.put("guestName", "Cliente: " + ticket.getGuest());
    map.put("reportDate", com.floreantpos.POSConstants.DATE + ": " + Application.formatDate(new Date()));
    map.put("grandSubtotal", Application.formatNumber(ticket.getSubtotalAmount()));
    map.put("taxAmount", Application.formatNumber(ticket.getTaxAmount()));
    map.put("notes", ticket.getNotes());
    map.put("transactionType", ticket.getTransactionType());
    map.put("transactionSubtype", ticket.getTransactionSubtype());
    map.put("cardType", ticket.getCardType());
    map.put("cardNumber", ticket.getCardNumber());
    map.put("paid", ticket.isPaid());
    map.put("printPartialPaymentInfo", printPartialPaymentInfo);
    map.put("dueAmount", Application.formatNumber(ticket.getDueAmount()));
    map.put("reportTime", "Impressão: " + dateFormat.format(currentTime.getTime()));
    map.put("createDate", com.floreantpos.POSConstants.DATE + ": " + Application.formatDate(ticket.getCreateDate()));
    map.put("printGuestBalance", printGuestBalance);
    map.put("guestBalance", Application.formatNumber(guestBalance));
    map.put("discountAmount", Application.formatNumber(ticket.getDiscountAmount()));
    map.put("grandSubtotalWithDiscount", Application.formatNumber(ticket.getSubtotalAmount() - ticket.getDiscountAmount()));
    map.put("guestTotalWithoutGratuity", Application.formatNumber(ticket.getTotalAmount() / ticket.getNumberOfGuests()));
    if (gratuityAmount > 0) {
      map.put("tipAmount", Application.formatNumber(gratuityAmount));
      if (ticket.getPaidAmount() > 0) {
        map.put("paidAmount", Application.formatNumber(ticket.getPaidAmount() + gratuityAmount));
      } else {
        map.put("paidAmount", Application.formatNumber(Double.valueOf(0)));
      }
      map.put("grandTotal", Application.formatNumber(ticket.getTotalAmount() + gratuityAmount));
      map.put("guestTotalWithGratuity", Application.formatNumber((ticket.getTotalAmount() + gratuityAmount) / ticket.getNumberOfGuests()));
    } else {
      map.put("grandTotal", Application.formatNumber(ticket.getTotalAmount()));
      map.put("paidAmount", Application.formatNumber(ticket.getPaidAmount()));
    }

    InputStream ticketReportStream = null;

    try {
      if (PrintConfig.isPrintReceiptWide()) {
        ticketReportStream = JReportPrintService.class.getResourceAsStream("/com/floreantpos/jreports/TicketReceiptReport.jasper");
      } else {
        ticketReportStream = JReportPrintService.class.getResourceAsStream("/com/floreantpos/jreports/TicketReceiptReportSmall.jasper");
      }

      JasperReport ticketReport = (JasperReport) JRLoader.loadObject(ticketReportStream);

      JasperPrint jasperPrint = JasperFillManager.fillReport(ticketReport, map, new JRTableModelDataSource(new TicketDataSource(ticket)));
      JasperPrintManager.printReport(jasperPrint, false);

      markTicketAsPrinted(ticket);

    } catch (JRException e) {
      logger.error(com.floreantpos.POSConstants.PRINT_ERROR, e);
    } finally {
      try {
        ticketReportStream.close();
      } catch (Exception x) {
      }
    }
  }

  public static void printTicketToKitchen(Ticket ticket) {
    Restaurant restaurant = RestaurantDAO.getInstance().get(Integer.valueOf(1));

    Calendar currentTime = Calendar.getInstance();
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");

    Boolean printAdditionalInfo = false;

    if (ticket.getGuest().equals("[Retira]") || !ticket.getGuest().equals(String.valueOf(ticket.getTableNumber())) || ticket.isVoided()) {
      printAdditionalInfo = true;
    }

    String additionalInfo = null;
    additionalInfo = "Cliente: " + ticket.getGuest();

    String headerLine = "";
    if (ticket.isVoided()) {
      headerLine = "* * * C A N C E L A D O * * *";
    } else {
      headerLine = restaurant.getName();
    }

    HashMap map = new HashMap();
    map.put("headerLine1", headerLine);

    map.put("checkNo", com.floreantpos.POSConstants.CHK_NO + ticket.getId());
    if (!Application.isSaveGuestName() && ticket.getTableNumber() > 0) {
      map.put("tableNo", Application.getControlTypeIdentifier() + ": " + ticket.getTableNumber());
    }
    map.put("guestCount", com.floreantpos.POSConstants.GUESTS_ + ticket.getNumberOfGuests());
    map.put("serverName", com.floreantpos.POSConstants.SERVER + ": " + ticket.getOwner());
    map.put("printAdditionalInfo", printAdditionalInfo);
    map.put("additionalInfo", additionalInfo);
    map.put("reportDate", com.floreantpos.POSConstants.DATE + ": " + Application.formatDate(new Date()));
    map.put("reportTime", "Impressão: " + dateFormat.format(currentTime.getTime()));
    map.put("createDate", com.floreantpos.POSConstants.DATE + ": " + Application.formatDate(ticket.getCreateDate()));

    InputStream ticketReportStream = null;

    try {
      if (PrintConfig.isPrintKitchenWide()) {
        ticketReportStream = JReportPrintService.class.getResourceAsStream("/com/floreantpos/jreports/KitchenReceipt.jasper");
      } else {
        ticketReportStream = JReportPrintService.class.getResourceAsStream("/com/floreantpos/jreports/KitchenReceiptSmall.jasper");
      }

      JasperReport ticketReport = (JasperReport) JRLoader.loadObject(ticketReportStream);

      JasperPrint jasperPrint = JasperFillManager.fillReport(ticketReport, map, new JRTableModelDataSource(new KitchenTicketDataSource(ticket)));

      JRPrinterAWT.printToKitchen = true;
      JasperPrintManager.printReport(jasperPrint, false);

      markItemsAsPrinted(ticket);

    } catch (JRException e) {
      logger.error(com.floreantpos.POSConstants.PRINT_ERROR, e);
    } finally {
      try {
        ticketReportStream.close();
      } catch (Exception x) {

      }
    }
  }

  private static void markTicketAsPrinted(Ticket ticket) {

    if (!ticket.isPrintedTicket()) {
      TicketDAO dao = new TicketDAO();
      Ticket printedTicket = dao.get(ticket.getId());
      printedTicket.setPrintedTicket(Boolean.TRUE);
      dao.update(printedTicket);
    }

  }

  private static void markItemsAsPrinted(Ticket ticket) {
    List<TicketItem> ticketItems = ticket.getTicketItems();
    if (ticketItems != null) {
      for (TicketItem ticketItem : ticketItems) {
        if (!ticketItem.isPrintedToKitchen()) {
          ticketItem.setPrintedToKitchen(true);
        }

        List<TicketItemModifierGroup> modifierGroups = ticketItem.getTicketItemModifierGroups();
        if (modifierGroups != null) {
          for (TicketItemModifierGroup modifierGroup : modifierGroups) {
            List<TicketItemModifier> modifiers = modifierGroup.getTicketItemModifiers();
            if (modifiers != null) {
              for (TicketItemModifier modifier : modifiers) {
                if (!modifier.isPrintedToKitchen()) {
                  modifier.setPrintedToKitchen(true);
                }
              }
            }
          }
        }
      }
    }
  }
}
